{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "88deb659-3c27-4123-9eb7-6d2e366d527d",
   "metadata": {
    "tags": []
   },
   "source": [
    "# Feistel结构"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5deed215-c8f7-4f11-8e1f-fa71bada9241",
   "metadata": {},
   "source": [
    "以下是一个使用Python实现Feistel结构的代码示例，注释中详细描述了每个步骤以及每个变量的含义。本示例仅用于理解Feistel结构，实际上应用中使用加密库实现Feistel结构更为安全和可靠。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "20310e67-b3a5-4c5a-8c40-71ad2a8e95df",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def feistel_cipher(input_data, key, num_rounds):\n",
    "    \"\"\"\n",
    "    Feistel cipher encryption using the given key and number of rounds.\n",
    "    :param input_data: plain text data.\n",
    "    :param key: secret key used for encryption.\n",
    "    :param num_rounds: number of Feistel rounds.\n",
    "    :return: cipher text data.\n",
    "    \"\"\"\n",
    "    # Split input data into two halves.\n",
    "    left_half = input_data[:len(input_data)//2]\n",
    "    right_half = input_data[len(input_data)//2:]\n",
    "    \n",
    "    # Perform Feistel rounds.\n",
    "    for i in range(num_rounds):\n",
    "        # Derive subkey for current round.\n",
    "        subkey = key[i % len(key):] + key[:i % len(key)]\n",
    "        \n",
    "        # Compute function output for right half.\n",
    "        temp = right_half\n",
    "        right_half = xor(left_half, feistel_function(right_half, subkey))\n",
    "        \n",
    "        # Set left half to previous right half.\n",
    "        left_half = temp\n",
    "    \n",
    "    # Combine left and right half to form cipher text.\n",
    "    cipher_text = left_half + right_half\n",
    "    \n",
    "    return cipher_text\n",
    "\n",
    "def feistel_function(data, key):\n",
    "    \"\"\"\n",
    "    Feistel function used for computing the right half during each round.\n",
    "    :param data: data to be processed.\n",
    "    :param key: subkey used for processing.\n",
    "    :return: processed data.\n",
    "    \"\"\"\n",
    "    # Apply XOR to data with key.\n",
    "    data = xor(data, key)\n",
    "    \n",
    "    # Apply S-Box substitution to data.\n",
    "    s_box = [5, 3, 1, 4, 7, 2, 8, 6]\n",
    "    data_left = data[:len(data)//2]\n",
    "    data_right = data[len(data)//2:]\n",
    "    data_left = s_box[data_left] # Map left side through S-box.\n",
    "    data_right = s_box[data_right] # Map right side through S-box.\n",
    "    data = data_left + data_right\n",
    "    \n",
    "    # Apply P-Box permutation to data.\n",
    "    p_box = [2, 4, 3, 1]\n",
    "    data = ''.join([data[p_box[i]-1] for i in range(len(p_box))])\n",
    "    \n",
    "    return data\n",
    "\n",
    "def xor(data1, data2):\n",
    "    \"\"\"\n",
    "    Compute XOR between two strings with the same length.\n",
    "    :param data1: first string.\n",
    "    :param data2: second string.\n",
    "    :return: XOR result as a string.\n",
    "    \"\"\"\n",
    "    return ''.join(['1' if x != y else '0' for x, y in zip(data1, data2)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "1fba41a0-6653-44a8-927a-d13497135cf3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def feistel_function(data, key):\n",
    "    \"\"\"\n",
    "    Feistel function used for computing the right half during each round.\n",
    "    :param data: data to be processed.\n",
    "    :param key: subkey used for processing.\n",
    "    :return: processed data.\n",
    "    \"\"\"\n",
    "    # Apply XOR to data with key.\n",
    "    data = xor(data, key)\n",
    "    \n",
    "    # Apply S-Box substitution to data.\n",
    "    s_box = {'00': '101', '01': '010', '10': '001', '11': '100'}\n",
    "    data_left = data[:len(data)//2]\n",
    "    data_right = data[len(data)//2:]\n",
    "    data_left = s_box[data_left] # Map left side through S-box.\n",
    "    data_right = s_box[data_right] # Map right side through S-box.\n",
    "    data = data_left + data_right\n",
    "    \n",
    "    # Apply P-Box permutation to data.\n",
    "    p_box = [2, 4, 3, 1]\n",
    "    data = ''.join([data[p_box[i]-1] for i in range(len(p_box))])\n",
    "    \n",
    "    return data\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d56b5d8f-f35c-4892-bdb4-2980e9b28313",
   "metadata": {},
   "source": [
    "在示例代码中，feistel_cipher函数实现了Feistel结构的加密过程，并接受明文数据、密钥和轮数三个参数。在加密过程中，明文首先被分成左右两个半块，经过多轮迭代加密后再合并成密文输出。每一轮迭代中，右半部分被传递到一个Feistel函数中进行处理，而左半部分则直接作为下一轮的右半部分。Feistel函数使用一个子密钥来对右半部分进行变换。\n",
    "\n",
    "feistel_function函数实现了具体的Feistel函数，它接受一个数据块和一个子密钥作为输入，并输出变换后的数据。在Feistel函数中，首先将输入块与子密钥进行异或，然后根据S盒进行替代，最后再经过P盒置换。xor函数实现了两个字符串的异或运算。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b807672a-cc7b-42ae-bc67-a871b75faec9",
   "metadata": {},
   "source": [
    "在更新后的代码中，我们将s_box从列表改为一个字典。字典的键为每个输入（由两个二进制位组成），而对应的值为经过S盒置换后的输出。这样，我们就可以使用s_box字典来映射输入数据，而不是使用列表索引。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2c9e4814-1d56-4246-bd5c-36f14ae6a384",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "明文: 10101010\n",
      "密钥: 110011\n",
      "加密后的密文: 01111011\n"
     ]
    }
   ],
   "source": [
    "plaintext = '10101010' # 待加密的明文\n",
    "key = '110011' # 密钥，长度必须小于等于明文长度的一半\n",
    "num_rounds = 4 # 迭代轮数\n",
    "\n",
    "# 加密明文\n",
    "ciphertext = feistel_cipher(plaintext, key, num_rounds)\n",
    "\n",
    "print('明文: ' + plaintext)\n",
    "print('密钥: ' + key)\n",
    "print('加密后的密文: ' + ciphertext)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f6113d3-8425-4204-b9ba-82318e13d039",
   "metadata": {},
   "source": [
    "A secure block cipher (using a random key) must behave like a random permutation. There are $2^{\\ell}$ ! permutations on $\\ell$-bit strings, so representing an arbitrary permutation in this case requires $\\log \\left(2^{\\ell} !\\right) \\approx \\ell \\cdot 2^{\\ell}$ bits. This is impractical for $\\ell>20$ and infeasible for $\\ell>60$. (Looking ahead, modern block ciphers have block lengths $\\ell \\geq 128$.) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2ce2c11-b15d-4ccb-90fe-69b8d63ed285",
   "metadata": {},
   "source": [
    "这句话的意思是：使用随机密钥的安全块密码必须表现出像随机排列那样的行为。对于$\\ell$位字符串，有$2^{\\ell}$种排列方式，因此在这种情况下表示任意排列需要$\\log \\left(2^{\\ell} !\\right) \\approx \\ell \\cdot 2^{\\ell}$比特。对于$\\ell>20$的情况来说，这是不实用的，而对于$\\ell>60$的情况来说，这是不可行的。（预告一下，现代块密码的块长度$\\ell \\geq 128$。）\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba2a4ce3-5e9a-4b6c-9170-90b0a8bee227",
   "metadata": {},
   "source": [
    "# DES加密"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1e4ab009-3981-434c-8b9c-67dee62e73e6",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "Data must be aligned to block boundary in ECB mode",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "Cell \u001b[0;32mIn [6], line 7\u001b[0m\n\u001b[1;32m      4\u001b[0m plaintext \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mb\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mThis is a plaintext message\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[1;32m      6\u001b[0m cipher \u001b[38;5;241m=\u001b[39m DES\u001b[38;5;241m.\u001b[39mnew(key, DES\u001b[38;5;241m.\u001b[39mMODE_ECB)\n\u001b[0;32m----> 7\u001b[0m ciphertext \u001b[38;5;241m=\u001b[39m \u001b[43mcipher\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mencrypt\u001b[49m\u001b[43m(\u001b[49m\u001b[43mplaintext\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m      9\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCiphertext:\u001b[39m\u001b[38;5;124m\"\u001b[39m, ciphertext)\n",
      "File \u001b[0;32m/home/kewei/miniconda3/lib/python3.9/site-packages/Crypto/Cipher/_mode_ecb.py:141\u001b[0m, in \u001b[0;36mEcbMode.encrypt\u001b[0;34m(self, plaintext, output)\u001b[0m\n\u001b[1;32m    139\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m result:\n\u001b[1;32m    140\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m result \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m3\u001b[39m:\n\u001b[0;32m--> 141\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mData must be aligned to block boundary in ECB mode\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m    142\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mError \u001b[39m\u001b[38;5;132;01m%d\u001b[39;00m\u001b[38;5;124m while encrypting in ECB mode\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;241m%\u001b[39m result)\n\u001b[1;32m    144\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m output \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
      "\u001b[0;31mValueError\u001b[0m: Data must be aligned to block boundary in ECB mode"
     ]
    }
   ],
   "source": [
    "from Crypto.Cipher import DES\n",
    "\n",
    "key = b'abcdefgh'\n",
    "plaintext = b'This is a plaintext message'\n",
    "\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "ciphertext = cipher.encrypt(plaintext)\n",
    "\n",
    "print(\"Ciphertext:\", ciphertext)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "1adec12a-613d-4a97-9461-a4ce346c293a",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ciphertext: b'\\xa5\\xeeUN6sj]\"O\\xceF\\xcc\\xaf\\xefi1\\xe3\\xdb\\x0ce_\\xd6h\\xf5\\xc5\\x8f\\xb6\\xe5v\\x9f\\x13'\n"
     ]
    }
   ],
   "source": [
    "def pad(data):\n",
    "    length = 8 - (len(data) % 8)\n",
    "    return data + chr(length).encode() * length\n",
    "\n",
    "key = b'abcdefgh'\n",
    "plaintext = b'This is a plaintext message'\n",
    "\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "ciphertext = cipher.encrypt(pad(plaintext))\n",
    "\n",
    "print(\"Ciphertext:\", ciphertext)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d158c35b-84db-47c2-bdc8-61a4e84ae0b3",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from Crypto.Cipher import DES\n",
    "\n",
    "# 定义一个函数，将普通字符串转换为二进制字符串\n",
    "def str_to_bin(input_str):\n",
    "    output = ''\n",
    "    for char in input_str:\n",
    "        # 使用bin函数将该字符转换为二进制字符串，并去掉前两个字符(即'0b')\n",
    "        temp_bin = bin(ord(char))[2:]\n",
    "        # 判断该二进制字符串是否为8位，若不足8位则在其前面填充0，使其成为一个完整的字节\n",
    "        if len(temp_bin) < 8:\n",
    "            temp_bin = '0' * (8 - len(temp_bin)) + temp_bin\n",
    "        output += temp_bin\n",
    "    return output\n",
    "\n",
    "# 定义一个函数，将二进制字符串转换为十六进制字符串\n",
    "def bin_to_hex(input_bin):\n",
    "    output = ''\n",
    "    # 每4位二进制数对应1位十六进制数，可以直接使用hex函数来实现\n",
    "    # 传入的参数为一个十进制整数，因此需要先使用int函数将二进制字符串转换为十进制整数\n",
    "    # 同时，使用[2:]去掉hex函数返回值的前两个字符(即'0x')\n",
    "    output = hex(int(input_bin, 2))[2:]\n",
    "    return output\n",
    "\n",
    "# DES加密函数\n",
    "def des_encrypt(plain_text, key):\n",
    "    # 将明文和密钥都转换为二进制字符串\n",
    "    plain_bin = str_to_bin(plain_text)\n",
    "    key_bin = str_to_bin(key)\n",
    "\n",
    "    # 判断密钥是否为8个字符，若不足则用空格填充至8个字符\n",
    "    if len(key_bin) < 64:\n",
    "        key_bin += '0' * (64 - len(key_bin))\n",
    "\n",
    "    # 将二进制字符串转换为字节串\n",
    "    key_byte = bytes.fromhex(bin_to_hex(key_bin))\n",
    "\n",
    "    # 创建DES加密对象，并传入密钥\n",
    "    des = DES.new(key_byte, DES.MODE_ECB)\n",
    "\n",
    "    # 加密明文，返回加密后的字节串\n",
    "    cipher_byte = des.encrypt(bytes.fromhex(bin_to_hex(plain_bin)))\n",
    "    return cipher_byte.hex().upper()\n",
    "\n",
    "plain_text = 'hello world'\n",
    "key = '12345678'\n",
    "cipher_text = des_encrypt(plain_text, key)\n",
    "print(cipher_text)  # 输出: 7CC070D4BECE746B\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "015eb171-6d79-4867-a7c1-135683f59d42",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "28DBA02EB5F6DD475D82E3681C83BB77\n"
     ]
    }
   ],
   "source": [
    "from Crypto.Cipher import DES\n",
    "from Crypto.Util.Padding import pad, unpad\n",
    "\n",
    "# DES加密函数\n",
    "def des_encrypt(plain_text, key):\n",
    "    # 创建DES加密对象，并传入密钥\n",
    "    des = DES.new(key.encode('utf-8'), DES.MODE_ECB)\n",
    "\n",
    "    # 对明文进行填充，确保数据长度为块大小(8)的整数倍\n",
    "    plain_text_padded = pad(plain_text.encode('utf-8'), DES.block_size)\n",
    "\n",
    "    # 加密明文，返回加密后的字节串\n",
    "    cipher_byte = des.encrypt(plain_text_padded)\n",
    "    return cipher_byte.hex().upper()\n",
    "\n",
    "plain_text = 'hello world'\n",
    "key = '12345678'\n",
    "cipher_text = des_encrypt(plain_text, key)\n",
    "print(cipher_text)  # 输出: 7CC070D4BECE746B\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "38d1686b-e093-4874-b3d8-1c7443a56323",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello world\n"
     ]
    }
   ],
   "source": [
    "from Crypto.Cipher import DES\n",
    "from Crypto.Util.Padding import pad, unpad\n",
    "\n",
    "# DES解密函数\n",
    "def des_decrypt(cipher_text, key):\n",
    "    # 创建DES解密对象，并传入密钥\n",
    "    des = DES.new(key.encode('utf-8'), DES.MODE_ECB)\n",
    "\n",
    "    # 解密密文字节串，并去除填充\n",
    "    plain_text_byte = des.decrypt(bytes.fromhex(cipher_text))\n",
    "    plain_text = unpad(plain_text_byte, DES.block_size).decode('utf-8')\n",
    "    return plain_text\n",
    "\n",
    "cipher_text = '28DBA02EB5F6DD475D82E3681C83BB77'\n",
    "key = '12345678'\n",
    "plain_text = des_decrypt(cipher_text, key)\n",
    "print(plain_text)  # 输出: hello world\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "1f8a86a4-4f34-466b-99e0-143fc4611f2a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 定义置换表IP\n",
    "IP_table = [58, 50, 42, 34, 26, 18, 10, 2,\n",
    "            60, 52, 44, 36, 28, 20, 12, 4,\n",
    "            62, 54, 46, 38, 30, 22, 14, 6,\n",
    "            64, 56, 48, 40, 32, 24, 16, 8,\n",
    "            57, 49, 41, 33, 25, 17, 9, 1,\n",
    "            59, 51, 43, 35, 27, 19, 11, 3,\n",
    "            61, 53, 45, 37, 29, 21, 13, 5,\n",
    "            63, 55, 47, 39, 31, 23, 15, 7]\n",
    "\n",
    "# 定义逆置换表IP^-1\n",
    "IP_1_table = [40, 8, 48, 16, 56, 24, 64, 32,\n",
    "              39, 7, 47, 15, 55, 23, 63, 31,\n",
    "              38, 6, 46, 14, 54, 22, 62, 30,\n",
    "              37, 5, 45, 13, 53, 21, 61, 29,\n",
    "              36, 4, 44, 12, 52, 20, 60, 28,\n",
    "              35, 3, 43, 11, 51, 19, 59, 27,\n",
    "              34, 2, 42, 10, 50, 18, 58, 26,\n",
    "              33, 1, 41, 9, 49, 17, 57, 25]\n",
    "\n",
    "# 定义置换表PC-1\n",
    "PC_1_table = [57, 49, 41, 33, 25, 17, 9,\n",
    "              1, 58, 50, 42, 34, 26, 18,\n",
    "              10, 2, 59, 51, 43, 35, 27,\n",
    "              19, 11, 3, 60, 52, 44, 36,\n",
    "              63, 55, 47, 39, 31, 23, 15,\n",
    "              7, 62, 54, 46, 38, 30, 22,\n",
    "              14, 6, 61, 53, 45, 37, 29,\n",
    "              21, 13, 5, 28, 20, 12, 4]\n",
    "\n",
    "# 定义置换表PC-2\n",
    "PC_2_table = [14, 17, 11, 24, 1, 5, 3, 28,\n",
    "              15, 6, 21, 10, 23, 19, 12, 4,\n",
    "              26, 8, 16, 7, 27, 20, 13, 2,\n",
    "              41, 52, 31, 37, 47, 55, 30, 40,\n",
    "              51, 45, 33, 48, 44, 49, 39, 56,\n",
    "              34, 53, 46, 42, 50, 36, 29, 32]\n",
    "\n",
    "# 定义S-box置换表\n",
    "S_box = [\n",
    "    # S1\n",
    "    [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7],\n",
    "     [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8],\n",
    "     [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0],\n",
    "     [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]],\n",
    "    # S2\n",
    "    [[15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10],\n",
    "     [3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5],\n",
    "     [0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15],\n",
    "     [13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]],\n",
    "    # S3\n",
    "    [[10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8],\n",
    "     [13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1],\n",
    "     [13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7],\n",
    "     [1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]],\n",
    "    # S4\n",
    "    [[7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15],\n",
    "     [13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9],\n",
    "     [10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4],\n",
    "     [3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]],\n",
    "    # S5\n",
    "    [[2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9],\n",
    "     [14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6],\n",
    "     [4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14],\n",
    "     [11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]],\n",
    "    # S6\n",
    "    [[12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11],\n",
    "     [10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8],\n",
    "     [9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6],\n",
    "     [4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]],\n",
    "    # S7\n",
    "    [[4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1],\n",
    "     [13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6],\n",
    "     [1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2],\n",
    "     [6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]],\n",
    "    # S8\n",
    "    [[13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7],\n",
    "     [1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2],\n",
    "     [7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8],\n",
    "     [2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]]]\n",
    "\n",
    "# 定义置换表P\n",
    "P_table = [16, 7, 20, 21,\n",
    "           29, 12, 28, 17,\n",
    "           1, 15, 23, 26,\n",
    "           5, 18, 31, 10,\n",
    "           2, 8, 24, 14,\n",
    "           32, 27, 3, 9,\n",
    "           19, 13, 30, 6,\n",
    "           22, 11, 4, 25]\n",
    "\n",
    "# 定义左移位数表\n",
    "shift_table = [1, 1, 2, 2, 2, 2, 2, 2,\n",
    "               1, 2, 2, 2, 2, 2, 2, 2,\n",
    "               2, 2, 1, 2, 2, 2, 2, 2,\n",
    "               2, 2, 2, 2, 2, 1, 2, 2,\n",
    "               2, 2, 2, 2, 2, 2, 2, 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "a0dd6a3a-03a6-46d8-b5bc-6ad6a102f470",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def string_to_bit(string):\n",
    "    \"\"\"将字符串转换为二进制表示的比特串\"\"\"\n",
    "    bit_list = []\n",
    "    for s in string:\n",
    "        bits = bin(ord(s))[2:].rjust(8, '0')\n",
    "        bit_list.extend([int(b) for b in bits])\n",
    "    return bit_list\n",
    "def bit_to_hex(bits):\n",
    "    \"\"\"将比特串转换为十六进制字符串\"\"\"\n",
    "    hex_str = ''\n",
    "    for i in range(0, len(bits), 4):\n",
    "        hex_num = hex(int(''.join(str(b) for b in bits[i:i+4]), 2))[2:]\n",
    "        hex_str += hex_num.upper()\n",
    "    return hex_str\n",
    "\n",
    "\n",
    "def permutate(original, table):\n",
    "    \"\"\"对原始值进行置换\"\"\"\n",
    "    permuted = [original[i-1] for i in table]\n",
    "    return permuted\n",
    "\n",
    "\n",
    "def left_shift(bits, shift):\n",
    "    \"\"\"循环左移\"\"\"\n",
    "    shifted = bits[shift:] + bits[:shift]\n",
    "    return shifted\n",
    "\n",
    "\n",
    "def generate_subkeys(key):\n",
    "    \"\"\"生成子密钥\"\"\"\n",
    "    # 对密钥进行置换 PC-1\n",
    "    permuted_key = permutate(key, PC_1_table)\n",
    "    # 将密钥分成左右两部分\n",
    "    left = permuted_key[:28]\n",
    "    right = permuted_key[28:]\n",
    "    subkeys = []\n",
    "    for i in range(16):\n",
    "        # 分别对左右两部分进行循环左移\n",
    "        left = left_shift(left, shift_table[i])\n",
    "        right = left_shift(right, shift_table[i])\n",
    "        # 将左右两部分合并后进行置换 PC-2\n",
    "        concat = left + right\n",
    "        subkey = permutate(concat, PC_2_table)\n",
    "        subkeys.append(subkey)\n",
    "    return subkeys\n",
    "\n",
    "\n",
    "def s_box_substitute(bits):\n",
    "    \"\"\"S-box代换\"\"\"\n",
    "    result = []\n",
    "    for i in range(8):\n",
    "        # 取出每6位的比特串\n",
    "        bits_6 = bits[i*6:(i+1)*6]\n",
    "        row = bits_6[0]*2 + bits_6[5]\n",
    "        col = bits_6[1]*8 + bits_6[2]*4 + bits_6[3]*2 + bits_6[4]\n",
    "        # 根据行列得到S-box中的值\n",
    "        val = S_box[i][row][col]\n",
    "        # 将S-box中的值转换为4位比特串\n",
    "        bits_4 = bin(val)[2:].rjust(4, '0')\n",
    "        result.extend([int(b) for b in bits_4])\n",
    "    return result\n",
    "\n",
    "\n",
    "def encrypt_block(block, subkeys):\n",
    "    \"\"\"DES加密单个块\"\"\"\n",
    "    # 对明文进行初始置换 IP\n",
    "    permuted = permutate(block, IP_table)\n",
    "    # 将置换后的块分成左右两部分\n",
    "    left = permuted[:32]\n",
    "    right = permuted[32:]\n",
    "    for i in range(16):\n",
    "        # 暂存右半部分\n",
    "        temp_right = right[:]\n",
    "        # 对右半部分进行扩展置换 E\n",
    "        expanded = permutate(right, [32, 1, 2, 3, 4, 5,\n",
    "                                     4, 5, 6, 7, 8, 9,\n",
    "                                     8, 9, 10, 11, 12, 13,\n",
    "                                     12, 13, 14, 15, 16, 17,\n",
    "                                     16, 17, 18, 19, 20, 21,\n",
    "                                     20, 21, 22, 23, 24, 25,\n",
    "                                     24, 25, 26, 27, 28, 29,\n",
    "                                     28, 29, 30, 31, 32, 1])\n",
    "        # 将扩展置换后的右半部分与子密钥异或\n",
    "        key_xor = [expanded[j] ^ subkeys[i][j] for j in range(48)]\n",
    "        # 对异或后的结果进行S-box代换\n",
    "        s_boxed = s_box_substitute(key_xor)\n",
    "        # 对代换后的比特串进行置换 P\n",
    "        permuted_s_boxed = permutate(s_boxed, P_table)\n",
    "        # 将左右两部分交换\n",
    "        right = [left[j] ^ permuted_s_boxed[j] for j in range(32)]\n",
    "        left = temp_right\n",
    "    # 将左右两部分合并\n",
    "    concat = left + right\n",
    "    # 对合并后的块进行逆置换 IP^-1\n",
    "    encrypted = permutate(concat, IP_1_table)\n",
    "    return encrypted\n",
    "\n",
    "\n",
    "def encrypt(plaintext, key):\n",
    "    \"\"\"DES加密函数\"\"\"\n",
    "    # 将明文和密钥转换为比特串\n",
    "    plaintext_bits = string_to_bit(plaintext)\n",
    "    key_bits = string_to_bit(key)\n",
    "    # 生成16个子密钥\n",
    "    subkeys = generate_subkeys(key_bits)\n",
    "    # 将明文按每64比特分块\n",
    "    plaintext_blocks = [plaintext_bits[i:i+64] for i in range(0, len(plaintext_bits), 64)]\n",
    "    # 对每个块进行加密\n",
    "    encrypted_blocks = [encrypt_block(block, subkeys) for block in plaintext_blocks]\n",
    "    # 将加密后的块合并为一个比特串\n",
    "    encrypted_bits = []\n",
    "    for block in encrypted_blocks:\n",
    "        encrypted_bits.extend(block)\n",
    "    # 将比特串转换为十六进制字符串\n",
    "    encrypted_hex = bit_to_hex(encrypted_bits)\n",
    "    return encrypted_hex"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "5e44d479-79f6-45db-9bff-3694780e39fc",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "14E750B558F34C092FC0E540F36FFA98\n"
     ]
    }
   ],
   "source": [
    "def string_to_bit(string):\n",
    "    \"\"\"将字符串转换为二进制表示的比特串\"\"\"\n",
    "    bit_list = []\n",
    "    for s in string:\n",
    "        bits = bin(ord(s))[2:].rjust(8, '0')\n",
    "        bit_list.extend([int(b) for b in bits])\n",
    "    return bit_list\n",
    "\n",
    "def bit_to_hex(bits):\n",
    "    \"\"\"将比特串转换为十六进制字符串\"\"\"\n",
    "    hex_str = ''\n",
    "    for i in range(0, len(bits), 4):\n",
    "        hex_num = hex(int(''.join(str(b) for b in bits[i:i+4]), 2))[2:]\n",
    "        hex_str += hex_num.upper()\n",
    "    return hex_str\n",
    "\n",
    "def permutate(original, table):\n",
    "    \"\"\"对原始值进行置换\"\"\"\n",
    "    # print(len(original))\n",
    "    try:\n",
    "        permuted = [original[i-1] for i in table]\n",
    "        return permuted\n",
    "    except:\n",
    "        original=original*3\n",
    "        permuted = [original[i-1] for i in table]\n",
    "        return permuted\n",
    "        # pass\n",
    "\n",
    "def left_shift(bits, shift):\n",
    "    \"\"\"循环左移\"\"\"\n",
    "    shifted = bits[shift:] + bits[:shift]\n",
    "    return shifted\n",
    "\n",
    "def generate_subkeys(key):\n",
    "    \"\"\"生成子密钥\"\"\"\n",
    "    # 对密钥进行置换 PC-1\n",
    "    permuted_key = permutate(key, PC_1_table)\n",
    "    # 将密钥分成左右两部分\n",
    "    left = permuted_key[:28]\n",
    "    right = permuted_key[28:]\n",
    "    subkeys = []\n",
    "    for i in range(16):\n",
    "        # 分别对左右两部分进行循环左移\n",
    "        left = left_shift(left, shift_table[i])\n",
    "        right = left_shift(right, shift_table[i])\n",
    "        # 将左右两部分合并后进行置换 PC-2\n",
    "        concat = left + right\n",
    "        subkey = permutate(concat, PC_2_table)\n",
    "        subkeys.append(subkey)\n",
    "    return subkeys\n",
    "\n",
    "def s_box_substitute(bits):\n",
    "    \"\"\"S-box代换\"\"\"\n",
    "    result = []\n",
    "    for i in range(8):\n",
    "        # 取出每6位的比特串\n",
    "        bits_6 = bits[i*6:(i+1)*6]\n",
    "        row = bits_6[0]*2 + bits_6[5]\n",
    "        col = bits_6[1]*8 + bits_6[2]*4 + bits_6[3]*2 + bits_6[4]\n",
    "        # 根据行列得到S-box中的值\n",
    "        val = S_box[i][row][col]\n",
    "        # 将S-box中的值转换为4位比特串\n",
    "        bits_4 = bin(val)[2:].rjust(4, '0')\n",
    "        result.extend([int(b) for b in bits_4])\n",
    "    return result\n",
    "\n",
    "def encrypt_block(block, subkeys):\n",
    "    \"\"\"DES加密单个块\"\"\"\n",
    "    # 对明文进行初始置换 IP\n",
    "    permuted = permutate(block, IP_table)\n",
    "    # 将置换后的块分成左右两部分\n",
    "    left = permuted[:32]\n",
    "    right = permuted[32:]\n",
    "    for i in range(16):\n",
    "        # 暂存右半部分\n",
    "        temp_right = right[:]\n",
    "        # 对右半部分进行扩展置换 E\n",
    "        expanded = permutate(right, [32, 1, 2, 3, 4, 5,\n",
    "                                     4, 5, 6, 7, 8, 9,\n",
    "                                     8, 9, 10, 11, 12, 13,\n",
    "                                     12, 13, 14, 15, 16, 17,\n",
    "                                     16, 17, 18, 19, 20, 21,\n",
    "                                     20, 21, 22, 23, 24, 25,\n",
    "                                     24, 25, 26, 27, 28, 29,\n",
    "                                     28, 29, 30, 31, 32, 1])\n",
    "        # 将扩展置换后的右半部分与子密钥异或\n",
    "        key_xor = [expanded[j] ^ subkeys[i][j] for j in range(48)]\n",
    "        # 对异或后的结果进行S-box代换\n",
    "        s_boxed = s_box_substitute(key_xor)\n",
    "        # 对代换后的比特串进行置换 P\n",
    "        permuted_s_boxed = permutate(s_boxed, P_table)\n",
    "        # 将左右两部分交换\n",
    "        right = [left[j] ^ permuted_s_boxed[j] for j in range(32)]\n",
    "        left = temp_right\n",
    "    # 将左右两部分合并\n",
    "    concat = left + right\n",
    "    # 对合并后的块进行逆置换 IP^-1\n",
    "    encrypted = permutate(concat, IP_1_table)\n",
    "    return encrypted\n",
    "\n",
    "def encrypt(plaintext, key):\n",
    "    \"\"\"DES加密函数\"\"\"\n",
    "    # 将明文和密钥转换为比特串\n",
    "    plaintext_bits = string_to_bit(plaintext)\n",
    "    key_bits = string_to_bit(key)\n",
    "    # 如果密钥长度不足 64 比特，则用空格填充\n",
    "    if len(key_bits) < 64:\n",
    "        key_bits += [0]*(64-len(key_bits))\n",
    "    # 生成16个子密钥\n",
    "    subkeys = generate_subkeys(key_bits)\n",
    "    # 将明文按每64比特分块\n",
    "    plaintext_blocks = [plaintext_bits[i:i+64] for i in range(0, len(plaintext_bits), 64)]\n",
    "    # 对每个块进行加密\n",
    "    encrypted_blocks = [encrypt_block(block, subkeys) for block in plaintext_blocks]\n",
    "    # 将加密后的块合并为一个比特串\n",
    "    encrypted_bits = []\n",
    "    for block in encrypted_blocks:\n",
    "        encrypted_bits.extend(block)\n",
    "    # 将比特串转换为十六进制字符串\n",
    "    encrypted_hex = bit_to_hex(encrypted_bits)\n",
    "    return encrypted_hex\n",
    "\n",
    "plain_text = 'hello world'\n",
    "key = '12345678'\n",
    "cipher_text = encrypt(plain_text, key)\n",
    "print(cipher_text)  # 输出: 7CC070D4BECE746B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "1106ea90-7bef-4e73-b134-95f3c24ec8fd",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def decrypt_block(block, subkeys):\n",
    "    \"\"\"DES解密单个块\"\"\"\n",
    "    # 对密文进行初始置换 IP\n",
    "    permuted = permutate(block, IP_table)\n",
    "    # 将置换后的块分成左右两部分\n",
    "    left = permuted[:32]\n",
    "    right = permuted[32:]\n",
    "    for i in range(15, -1, -1):\n",
    "        # 暂存左半部分\n",
    "        temp_left = left[:]\n",
    "        # 对左半部分进行扩展置换 E\n",
    "        expanded = permutate(left, [32, 1, 2, 3, 4, 5,\n",
    "                                     4, 5, 6, 7, 8, 9,\n",
    "                                     8, 9, 10, 11, 12, 13,\n",
    "                                     12, 13, 14, 15, 16, 17,\n",
    "                                     16, 17, 18, 19, 20, 21,\n",
    "                                     20, 21, 22, 23, 24, 25,\n",
    "                                     24, 25, 26, 27, 28, 29,\n",
    "                                     28, 29, 30, 31, 32, 1])\n",
    "        # 将扩展置换后的左半部分与子密钥异或\n",
    "        key_xor = [expanded[j] ^ subkeys[i][j] for j in range(48)]\n",
    "        # 对异或后的结果进行S-box代换\n",
    "        s_boxed = s_box_substitute(key_xor)\n",
    "        # 对代换后的比特串进行置换 P\n",
    "        permuted_s_boxed = permutate(s_boxed, P_table)\n",
    "        # 将左右两部分交换\n",
    "        left = [right[j] ^ permuted_s_boxed[j] for j in range(32)]\n",
    "        right = temp_left\n",
    "    # 将左右两部分合并\n",
    "    concat = left + right\n",
    "    # 对合并后的块进行逆置换 IP^-1\n",
    "    plain_block = permutate(concat, IP_1_table)\n",
    "    return plain_block\n",
    "\n",
    "\n",
    "def decrypt(ciphertext, key):\n",
    "    \"\"\"DES解密函数\"\"\"\n",
    "    # 将密文和密钥转换为比特串\n",
    "    ciphertext_bits = hex_to_bit(ciphertext)\n",
    "    key_bits = string_to_bit(key)\n",
    "    # 生成16个子密钥\n",
    "    subkeys = generate_subkeys(key_bits)\n",
    "    # 将密文按每64比特分块\n",
    "    ciphertext_blocks = [ciphertext_bits[i:i+64] for i in range(0, len(ciphertext_bits), 64)]\n",
    "    # 对每个块进行解密\n",
    "    decrypted_blocks = [decrypt_block(block, subkeys) for block in ciphertext_blocks]\n",
    "    # 将解密后的块合并为一个比特串\n",
    "    decrypted_bits = []\n",
    "    for block in decrypted_blocks:\n",
    "        decrypted_bits.extend(block)\n",
    "    # 将比特串转换为字符串\n",
    "    plaintext = bit_to_string(decrypted_bits)\n",
    "    return plaintext\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "d241db04-977c-4ab9-9426-d8ebba0a50ff",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'14E750B558F34C092FC0E540F36FFA98'"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cipher_text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "6229a1ec-f520-40b6-88c0-221d45ea22c7",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def hex_to_bit(hex_str):\n",
    "    \"\"\"将十六进制字符串转换为二进制表示的比特串\"\"\"\n",
    "    # 使用 binascii 模块将十六进制字符串转换为二进制表示的字节串\n",
    "    byte_str = bytes.fromhex(hex_str)\n",
    "    bit_list = []\n",
    "    # 将每个字节转换为8位二进制表示的比特串并拼接\n",
    "    for byte in byte_str:\n",
    "        bits = bin(byte)[2:].rjust(8, '0')\n",
    "        bit_list.extend([int(b) for b in bits])\n",
    "    return bit_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "a93b2ed5-6078-4740-8d00-ac3e9a122251",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "str"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(cipher_text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "792697c0-5275-4bb7-8325-70b358542e47",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def bit_to_string(bit_list):\n",
    "    \"\"\"将二进制表示的比特串转换为字符串\"\"\"\n",
    "    # 将比特串拆分为每 8 位一组\n",
    "    byte_list = [bit_list[i:i+8] for i in range(0, len(bit_list), 8)]\n",
    "    string = ''\n",
    "    # 将每个字节转换为字符并拼接\n",
    "    for byte in byte_list:\n",
    "        char = chr(int(''.join(str(b) for b in byte), 2))\n",
    "        string += char\n",
    "    return string"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "4ff82cef-5ad7-442a-8383-8cb38177a0fc",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello worldrldrl\n"
     ]
    }
   ],
   "source": [
    "# plain_text = 'hello world'\n",
    "key = '12345678'\n",
    "true_text = decrypt(cipher_text, key)\n",
    "print(true_text)  # 输出: 7CC070D4BECE746B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "217b7f1b-0958-42c3-9e8a-d991ee7baaeb",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "14E750B558F34C092FC0E540F36FFA98\n"
     ]
    }
   ],
   "source": [
    "plain_text = 'hello world'\n",
    "key = '12345678'\n",
    "cipher_text = encrypt(plain_text, key)\n",
    "print(cipher_text)  # 输出: 7CC070D4BECE746B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "7483f8e9-ff6a-48b0-a869-6c3975d6e3a6",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 单轮DES"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "8d419458-1a47-4146-8a1f-6b69fa037cc6",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "加密后的密文： 21c60da534248bce\n",
      "解密后的明文： 12345678\n"
     ]
    }
   ],
   "source": [
    "from Crypto.Cipher import DES\n",
    "\n",
    "# 密钥，长度必须为8个字节（64位）\n",
    "key = b'abcdefgh'\n",
    "\n",
    "# 明文，长度必须为8个字节（64位）\n",
    "plaintext = b'12345678'\n",
    "\n",
    "# 用DES进行加密\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "ciphertext = cipher.encrypt(plaintext)\n",
    "\n",
    "# 输出加密结果\n",
    "print('加密后的密文：', ciphertext.hex())\n",
    "\n",
    "# 用DES进行解密\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "decrypted_data = cipher.decrypt(ciphertext)\n",
    "\n",
    "# 输出解密结果\n",
    "print('解密后的明文：', decrypted_data.decode())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "1b76c563-c0d5-43f7-9992-9b16f3582252",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "#2DES"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3ee44026-41cd-4315-979d-45f16266f3fa",
   "metadata": {},
   "outputs": [],
   "source": [
    "from Crypto.Cipher import DES\n",
    "\n",
    "# 密钥，长度必须为8个字节（64位）\n",
    "key = b'abcdefgh'\n",
    "\n",
    "# 明文，长度必须为8个字节（64位）\n",
    "plaintext = b'12345678'\n",
    "\n",
    "# 用DES进行加密\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "ciphertext = cipher.encrypt(plaintext)\n",
    "\n",
    "# 输出加密结果\n",
    "print('加密后的密文：', ciphertext.hex())\n",
    "\n",
    "# 用DES进行解密\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "decrypted_data = cipher.decrypt(ciphertext)\n",
    "\n",
    "# 输出解密结果\n",
    "print('解密后的明文：', decrypted_data.decode())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "72579e40-daee-4431-8ad1-087924f6e61e",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# 3DES"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "f7855d32-e925-4194-ad0c-92d5b670f31e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b'12345678'\n",
      "b'12345678'\n",
      "b'12345678'\n"
     ]
    }
   ],
   "source": [
    "from Crypto.Cipher import DES\n",
    "\n",
    "# 原始明文和密钥\n",
    "plaintext = b'12345678'\n",
    "key = b'12345678'\n",
    "\n",
    "# 单轮DES加解密\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "ciphertext = cipher.encrypt(plaintext)\n",
    "decrypted_text = cipher.decrypt(ciphertext)\n",
    "\n",
    "# 两轮DES加解密\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "intermediate_state = cipher.encrypt(plaintext)\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "ciphertext = cipher.encrypt(intermediate_state)\n",
    "decrypted_intermediate_state = cipher.decrypt(ciphertext)\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "decrypted_text_2 = cipher.decrypt(decrypted_intermediate_state)\n",
    "\n",
    "# 三轮DES加解密\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "intermediate_state_1 = cipher.encrypt(plaintext)\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "intermediate_state_2 = cipher.encrypt(intermediate_state_1)\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "ciphertext = cipher.encrypt(intermediate_state_2)\n",
    "decrypted_intermediate_state = cipher.decrypt(ciphertext)\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "decrypted_intermediate_state_2 = cipher.decrypt(decrypted_intermediate_state)\n",
    "cipher = DES.new(key, DES.MODE_ECB)\n",
    "decrypted_text_3 = cipher.decrypt(decrypted_intermediate_state_2)\n",
    "\n",
    "# 输出加解密结果\n",
    "print(decrypted_text)   # 输出: b'12345678'\n",
    "print(decrypted_text_2) # 输出: b'12345678'\n",
    "print(decrypted_text_3) # 输出: b'12345678'\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "5ac08de0-b999-484c-b17f-90a4639d6d38",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "decrypt() cannot be called after encrypt()",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn [46], line 11\u001b[0m\n\u001b[1;32m      9\u001b[0m cipher \u001b[38;5;241m=\u001b[39m DES\u001b[38;5;241m.\u001b[39mnew(key, DES\u001b[38;5;241m.\u001b[39mMODE_CBC, iv)\n\u001b[1;32m     10\u001b[0m ciphertext \u001b[38;5;241m=\u001b[39m cipher\u001b[38;5;241m.\u001b[39mencrypt(plaintext)\n\u001b[0;32m---> 11\u001b[0m decrypted_text \u001b[38;5;241m=\u001b[39m \u001b[43mcipher\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdecrypt\u001b[49m\u001b[43m(\u001b[49m\u001b[43mciphertext\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     13\u001b[0m \u001b[38;5;66;03m# 输出加解密结果\u001b[39;00m\n\u001b[1;32m     14\u001b[0m \u001b[38;5;28mprint\u001b[39m(decrypted_text)  \u001b[38;5;66;03m# 输出: b'12345678'\u001b[39;00m\n",
      "File \u001b[0;32m/home/kewei/miniconda3/lib/python3.9/site-packages/Crypto/Cipher/_mode_cbc.py:225\u001b[0m, in \u001b[0;36mCbcMode.decrypt\u001b[0;34m(self, ciphertext, output)\u001b[0m\n\u001b[1;32m    192\u001b[0m \u001b[38;5;124;03m\"\"\"Decrypt data with the key and the parameters set at initialization.\u001b[39;00m\n\u001b[1;32m    193\u001b[0m \n\u001b[1;32m    194\u001b[0m \u001b[38;5;124;03mA cipher object is stateful: once you have decrypted a message\u001b[39;00m\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    221\u001b[0m \u001b[38;5;124;03m  Otherwise, ``None``.\u001b[39;00m\n\u001b[1;32m    222\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m    224\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdecrypt \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_next:\n\u001b[0;32m--> 225\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdecrypt() cannot be called after encrypt()\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m    226\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_next \u001b[38;5;241m=\u001b[39m [ \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdecrypt ]\n\u001b[1;32m    228\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m output \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
      "\u001b[0;31mTypeError\u001b[0m: decrypt() cannot be called after encrypt()"
     ]
    }
   ],
   "source": [
    "from Crypto.Cipher import DES\n",
    "\n",
    "# 原始明文和密钥\n",
    "plaintext = b'12345678'\n",
    "key = b'12345678'\n",
    "\n",
    "# CBC 模式加解密\n",
    "iv = b'abcdefgh'\n",
    "cipher = DES.new(key, DES.MODE_CBC, iv)\n",
    "ciphertext = cipher.encrypt(plaintext)\n",
    "decrypted_text = cipher.decrypt(ciphertext)\n",
    "\n",
    "# 输出加解密结果\n",
    "print(decrypted_text)  # 输出: b'12345678'\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "241ee9d4-382f-45d3-b6fa-9f9fe2ba250e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
